<template>
  <div class="user-select-component">
    <el-select
      v-select-scroll="!collapseTags"
      v-loadmore="loadmore"
      ref="userSelect"
      v-model="selectData"
      :disabled="disabled"
      :multiple="multiple"
      :filter-method="filterData"
      :filterable="filterable"
      :collapse-tags="collapseTags"
      :placeholder="placeholder"
      :clearable="clearable"
      :allow-create="allowCreate"
      :multiple-limit="multipleLimit"
      :value-key="valueType==='object'?keyName:''"
      :popper-class="'global-select-down '+extendClass"
      :loading="queryLoading"
      :style="{width: setInputWidth}"
      class="filterableSelect remoteRequestClient"
      size="small"
      @focus="$emit('focus')"
      @blur="searchVal = ''"
      @clear="clear"
      @hook:mounted="cancelReadOnly"
      @change="selectChange"
      @visible-change="visibleChange"
    >
      <el-option v-if="addNew" :value="-9999" class="select-extend-btn" disabled>
        <div class="select-extend-btn-text" @click="handleAddNew">{{ addNewStr }}</div>
      </el-option>
      <Options
        v-model="defaultList"
        :key-name="keyName"
        :label-name="labelName"
        :value-type="valueType"
        :extern-key="externKey"
        :open-tool-tip="openToolTip"
        :foot-tag="footTag"
        :foot="foot"
        :not-show-label-foot="notShowLabelFoot"
        :custom-label="customLabel"
        :is-can-delete="isCanDelete"
        :show-check-user="showCheckUser"
        :extend-key-name="extendKeyName"
        @onDelete="onDelete" />
      <!-- 用于保存选中的数据，但是不显示在列表 -->
      <template v-if="selectDataList && selectDataList.length">
        <Options
          v-model="selectDataList"
          :key-name="keyName"
          :label-name="labelName"
          :value-type="valueType"
          :extern-key="externKey"
          :foot-tag="footTag"
          :foot="foot"
          :show-check-user="showCheckUser"
          :not-show-label-foot="notShowLabelFoot"
          :extend-key-name="extendKeyName"
          style="display:none;" />
      </template>
      <!-- 用于保存选中的数据，但是不显示在列表，少数需求会用到这个 -->
      <template v-if="hideSelectList">
        <Options
          v-model="hideSelectList"
          :key-name="keyName"
          :label-name="labelName"
          :value-type="valueType"
          :extern-key="externKey"
          :foot-tag="footTag"
          :foot="foot"
          :show-check-user="showCheckUser"
          :not-show-label-foot="notShowLabelFoot"
          :extend-key-name="extendKeyName"
          style="display:none;" />
      </template>
      <Options
        v-model="listDataItems"
        :key-name="keyName"
        :label-name="labelName"
        :value-type="valueType"
        :extern-key="externKey"
        :open-tool-tip="openToolTip"
        :foot-tag="footTag"
        :foot="foot"
        :show-check-user="showCheckUser"
        :is-can-delete="isCanDelete"
        :not-show-label-foot="notShowLabelFoot"
        :custom-label="customLabel"
        :extend-key-name="extendKeyName"
        @onDelete="onDelete" />
      <div v-if="!userLoading && listData.items && !listData.items.length" class="no-data-tip">暂无数据</div>
      <div v-if="!isNoLoading && userLoading" class="loading-container"><i class="el-icon-loading"/></div>
    </el-select>
  </div>
</template>

<script>
import { getUserList } from '@/api/user';
import ElMessage from '@/utils/message';
import Options from './selectWithUserLoad/options';
import { mapState } from 'vuex';

export default {
  components: { Options },
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: String | Number,
      default: ''
    },
    defaultList: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 当选中的项不在第一页时，可以使用这个属性：使输入框能够匹配到数据，该数据不会显示在下拉选项中
    hideSelectList: {
      type: Array,
      default: () => {
        return [];
      }
    },
    extendParams: { // 传给接口额外的参数
      type: Object,
      default: null
    },
    placeholder: {
      type: String,
      default: '请选择'
    },
    labelName: { // label的字段
      type: String,
      default: 'userName'
    },
    keyName: { // key的字段
      type: String,
      default: 'id'
    },
    foot: {
      type: String,
      default: ''
    },
    notShowLabelFoot: {
      type: Boolean,
      default: false
    },
    externKey: {
      type: String,
      default: ''
    },
    multiple: { // 多选
      type: Boolean,
      default: false
    },
    multipleLimit: { // 多选限制
      type: Number,
      default: 0
    },
    filterable: { // 是否开启搜索
      type: Boolean,
      default: true
    },
    collapseTags: { // 折叠tag
      type: Boolean,
      default: true
    },
    loadmoreMethod: { // 加载的方法
      type: Function,
      default: getUserList
    },
    perPage: { // 加载时，默认的页容
      type: Number,
      default: 15
    },
    clearable: { // 是否可以清除
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    valueType: { // 如果值为object,则值使用对象传输
      type: String,
      default: ''
    },
    initLoad: {
      type: Boolean,
      default: true
    },
    isNoLoading: {
      type: Boolean,
      default: false
    },
    extendClass: {
      type: String,
      default: ''
    },
    isDynamicLoad: {
      type: Boolean,
      default: false
    },
    visibleChangeData: { // 下拉框出现时是否重新请求数据（前提：列表数据为空）
      type: Boolean,
      default: false
    },
    addNew: { // 下拉框第一个点击事件，目前用于添加新的供应商
      type: Boolean,
      default: false
    },
    openToolTip: { // 是否展示列表的tooltip
      type: Boolean,
      default: false
    },
    addNewStr: {
      type: String,
      default: '添加新供应商'
    },
    allowCreate: {
      type: Boolean,
      default: false
    },
    userStatus: {
      type: Number,
      default: -1
    },
    needLoadmore: { // 是否需要下拉加载更多
      type: Boolean,
      default: true
    },
    customLabel: { // 是否展示自定义的选项(合同-签约对方选项展示)
      type: Boolean,
      default: false
    },
    extendKeyName: { // 额外做key的字符
      type: String,
      default: ''
    },
    footTag: {
      type: String,
      default: '[]'
    },
    isCanDelete: {
      type: Boolean,
      default: false
    },
    showCheckUser: {
      type: Boolean,
      default: false
    },
    inputWidthIsAuto: { // 输入宽度自适应
      type: Boolean,
      default: false
    },
    autoInputDefaultWidth: { // 输入宽度自适应时的初始宽度
      type: String,
      default: '5px'
    },
    autoInputMaxWidth: { // 输入宽度自适应时的最大宽度
      type: Number,
      default: 60
    },
    defaultFirstOption: { // 默认预选中第一项
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      userLoading: false,
      listData: { items: [] },
      selectDataList: [],
      selectDataItem: {},
      init: true,
      searchVal: '',
      inputWidth: '',
      queryLoading: false // 接口数据loading
    };
  },
  computed: {
    ...mapState({
      'showMobilePage': state => state.app.showMobilePage
    }),
    selectData: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('change', val);
      }
    },
    setInputWidth() {
      if (this.inputWidthIsAuto) return this.inputWidth || this.autoInputDefaultWidth;
      return '';
    },
    listDataItems() {
      return this.handelDefaultUserList(this.listData.items);
    }
  },
  watch: {
    defaultList: {
      handler(newVal) {
        this.selectDataList = [...newVal];
      },
      immediate: true
    }
  },
  created() {
    if (this.initLoad && !this.isDynamicLoad) this.getListData();
  },
  methods: {
    keyItem(item, foot) {
      if (item[foot]) {
        return `[${item[foot]}]`;
      }
      return '';
    },
    clear() {
      this.getListData();
      this.$emit('clear');
    },
    onDelete(key) {
      this.$emit('onDelete', key);
    },
    selectChange(value) {
      this.searchVal = '';
      const listData = this.listData.items;
      if (this.valueType === 'object') {
        this.selectDataList = value;
        this.$emit('changeMethod', this.selectDataList);
        return;
      }
      if (typeof value !== 'object') {
        this.selectDataItem = listData.find(i => {
          return i[this.keyName] === value;
        });
        let selectDataItem = {};
        if (value && this.defaultList.length && this.defaultList[0].id === value) {
          selectDataItem = this.defaultList[0];
        } else {
          selectDataItem = this.selectDataItem;
        }
        this.$emit('changeMethod', selectDataItem);
        return false;
      }
      if (value && value.length > 0) {
        listData.forEach(i => {
          if (value.includes(i.id)) {
            this.selectDataList.push(i);
          }
        });
        this.selectDataList = this.selectDataList.filter(i => {
          return value.includes(i.id);
        });
        this.selectDataList = this.uniqe(this.selectDataList);
      } else {
        this.selectDataList = [];
      }
      if (this.listData && this.listData.items.length === 0) this.getListData();
      this.$emit('changeMethod', this.selectDataList);
      const cacheList = this.selectDataList.map(item => {
        return {
          id: item.id,
          [this.labelName]: item[this.labelName]
        };
      });
      this.$emit('selectDataSave', JSON.stringify(cacheList)); // 缓存核算上一次填写的审批人员
    },
    // 去重
    uniqe(arr) {
      const result = [];
      const obj = {};
      for (let i = 0; i < arr.length; i++) {
        if (!obj[arr[i].id]) {
          result.push(arr[i]);
          obj[arr[i].id] = true;
        }
      }
      return result;
    },
    loadmore(val) {
      const listData = this.listData;
      const currentPage = listData.page;
      if (listData.items) {
        const isMax = listData.items.length >= listData.total;
        if (!isMax && !this.userLoading && listData.perPage !== 1000 && this.needLoadmore) {
          this.getListData(currentPage + 1, this.searchVal);
        }
      }
    },
    filterData(val) {
      if (this.inputWidthIsAuto) { // 计算自动宽度
        if (val === '') {
          this.inputWidth = this.autoInputDefaultWidth;
        } else {
          this.inputWidth = Math.min((val.length * 14 + 4), this.autoInputMaxWidth) + 'px';
        }
        this.$emit('getCurSearchVal', val);
      }
      const that = this;
      function callbackFn(that, val) {
        if (that.init && that.isDynamicLoad) return;
        that.searchVal = val;
        that.$emit('searchKeyword', val);
        that.getListData(1, val);
      }
      (_.debounce(function(callbackFn) {
        callbackFn && callbackFn(that, val);
      }, 200))(callbackFn(that, val));
    },
    getListData(page = 1, name = '') {
      this.userLoading = true;
      const params = { page, perPage: this.perPage, userStatus: this.userStatus };
      if (name) params[this.labelName] = name;
      if (name) params.userName = name;
      if (this.init) params.notShowNoAuthTip = true;
      if (this.extendParams) Object.assign(params, this.extendParams);
      if (page === 1 && this.isDynamicLoad) this.queryLoading = true;
      this.loadmoreMethod(params).then(({ data }) => {
        if (this.defaultFirstOption) {
          this.$refs['userSelect'].hoverIndex = 0;
        }
        this.userLoading = false;
        this.queryLoading = false;
        if (page > 1 && this.listData.items) {
          data.items = this.listData.items.concat(data.items);
        }
        this.listData = data;
        this.init = false;
      }).catch(err => {
        if (err && err.message && !this.initLoad && !this.init) ElMessage.error(err.message);
        this.queryLoading = false;
        this.init = false;
        console.log('err', err);
      });
    },
    // 从用户列表中去除 defaultList 已经有的数据
    handelDefaultUserList(listData) {
      let res = [];
      if (listData && listData.length) {
        const ids = this.defaultList.map(i => i[this.keyName]);
        res = listData.filter(i => {
          return !ids.includes(i[this.keyName]);
        });
      }
      return res;
    },
    visibleChange(e) {
      this.$emit('visibleChange', e);
      if (e && this.visibleChangeData && (!this.listData || this.listData.items.length === 0)) {
        this.getListData();
      }
      if (this.showMobilePage) { this.cancelReadOnly(e); }
    },
    handleAddNew() {
      this.$emit('addNewClick');
    },
    // 解决ios无法唤起键盘
    cancelReadOnly(value) {
      this.$nextTick(() => {
        if (!value) {
          const { userSelect } = this.$refs;
          const input = userSelect.$el.querySelector('.el-input__inner');
          input.removeAttribute('readonly');
        }
      });
    },
    inputFocus() {
      this.$refs['userSelect'].focus();
    },
    inputBlur() {
      this.$refs['userSelect'].blur();
    }
  }
};
</script>

<style lang="scss" scoped>
.loading-container {
  width: 100%;
  text-align: center;
  i {
    color: #999;
  }
}
.no-data-tip {
  width: 100%;
  text-align: center;
  height: 34px;
  line-height: 34px;
  color: #999;
}
.user-select-component {
  &::v-deep {
    .filterableSelect {
      width: 100%;
    }
    .el-tag.el-tag--info {
      color: #406eff;
      background: #eff3fb;
    }
    .el-tag__close{
      flex-shrink: 0;
      // right:-1px !important;
    }
  }
}
.select-extend-btn {
  cursor: pointer !important;
  border-bottom: 1px solid #ddd;
  .select-extend-btn-text {
    color: #406eff;
  }
}
</style>
